import {createReducer} from 'redux-act';
import _ from 'lodash';
import u from 'updeep';
import {createAction2} from '../util';
import cache, {check} from '../util/cache';
import {bed, up, get, nullKey} from '../util/bed';
import * as ajax from '../util/ajax';
import * as http from '../util/http';
const [
    loadAll,
    load,
    create,
    modify,
    del
] = [
    'DICT_LOADALL',
    'DICT_LOAD',
    'DICT_CREATE',
    'DICT_MODIFY',
    'DICT_DEL'
].map(createAction2);

export const actions = {
    loadAll: (types, cb) => {
        const keys = _.reduce(_.keys(types), (res, v) => {
            res[v] = `dict.${v}`;
            return res;
        }, {});
        return check('dict', keys, (ks, cacheData) => {
            if (ks.length) {
                const q = {
                    _where: {
                        whereIn: ['type', ks]
                    }
                };
                return bed(ajax.get(http.makeUrl(`/dict/`, q)), loadAll, {types, ks, cacheData, cb});
            }
            cb(types, cacheData);
            return Promise.resolve();
        });
    },
    load: ({params: {type} = {}}, q = {}, forceLoad) => cache(
        'dict'
        , `dict.${type}`
        , bed(
            ajax.get(http.makeUrl(`/dict/${type}`, q)),
            load,
            {
                key: type
            }
        )
        , {forceLoad}
    ),
    create: (data, {params: {type} = {}}) => bed(ajax.post(`/dict/${type}`, data), create, {
        key: type,
        data
    }),
    modify: (data, {params: {type} = {}}) => bed(ajax.put(`/dict/${type}`, data), modify, {
        key: type,
        data
    }),
    del: (data, {params: {type} = {}}) => bed(ajax.del(`/dict/${type}/${data.Id}`), del, {
        key: type,
        data
    })
};

export default createReducer({
    [loadAll]: (state, payload, {done, types, cacheData, cb}) => {
        let result = up(state, payload, '*');
        if (done) {
            const {data: allData} = payload;
            const dataByTypes = _.reduce(allData, (res, v) => {
                const typeDatas = res[v.Type] || (res[v.Type] = []);
                typeDatas.push(v);
                return res;
            }, {});
            result = _.reduce(dataByTypes, (res, v, k) => {
                cacheData[k] = v;
                return u({[k]: v}, res);
            }, result);
            if (cb) {
                cb(types, cacheData);
            }
        }
        return result;
    },
    [load]: get,
    [create]: (state, payload, {data, key}) => {
        let result = up(state, payload, nullKey);
        const {data: Id} = payload;
        if (Id) {
            data.Id = Id;
            result = u({[key]: (arr) => [].concat(arr, [data])}, result);
        }
        return result;
    },
    [modify]: (state, payload, {data, key, done}) => {
        let result = up(state, payload);
        if (done) {
            if (key === 'diagnosis') {
                result = u({[key]: {data: u.map(d => (d.Id === data.Id ? data : d))}}, result);
            } else {
                result = u({[key]: u.map(d => (d.Id === data.Id ? data : d))}, result);
            }
        }
        return result;
    },
    [del]: (state, payload, {data, key, done}) => {
        let result = up(state, payload);
        if (done) {
            result = u({[key]: u.reject(d => d.Id === data.Id)}, result);
        }
        return result;
    }
}, {});
